"use strict"

module.exports = function(options){
  let template   = require("es6-template-strings")
    ,_           = require("lodash")
    ,webRequest  = require('request')
    ,log4js      = require('log4js')
    ,logger      = log4js.getLogger("qywx-auth")
    ,debug       = require('debug')("qywx-auth")
    ,rp          = require("request-promise")
    ,QywxAccessTokenHolder = require("./QywxAccessTokenHolder");

  const GET_ACCESS_TOKEN_URL = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?"
                                    + "corpid=${corpId}&corpsecret=${corpSecret}";

  var QywxAccessTokenClient = function(corpId, corpSecret){
    if( !(this instanceof QywxAccessTokenClient) ){
      return new QywxAccessTokenClient(corpId, corpSecret);
    }else{
      this.corpId         = corpId;
      this.corpSecret     = corpSecret;
      this.lockedForQuery = false;
      this.lockedAt       = null;
      this.holder         = new QywxAccessTokenHolder();
      this.targetUrl =
            template(GET_ACCESS_TOKEN_URL, { corpId: this.corpId, corpSecret: this.corpSecret });

    }
  }

  QywxAccessTokenClient.prototype.lockedTimeout = function(){
      return  !!( this.lockedAt === null || (_.now() - this.lockedAt) > 2 * 60 * 1000 );
  }

  QywxAccessTokenClient.prototype.get = function(cb){
    var client = this;

    if( client.holder.token && !client.holder.expiring() ){
      return cb(null, {
        accessToken: client.holder.token
      });
    }

    if(!client.lockedForQuery || client.lockedTimeout()){
        client.lockedForQuery = true;
        client.lockedAt = _.now();
        var rpOptions = {
            uri: client.targetUrl,
            qs: {
                //access_token: 'xxxxx xxxxx' // -> uri + '?access_token=xxxxx%20xxxxx'
            },
            headers: {
                //'User-Agent': 'Request-Promise'
            },
            json: true // Automatically parses the JSON string in the response
        };

        rp(rpOptions).then(function(data){
          //For lock - if we success to retrieve data there is no need to unlock,
          // Just wait for lock timeout
          client.holder.set(data.access_token, data.expires_in);
          return cb(null, {
            accessToken: client.holder.token
          });
        })
        .catch(function(err){
          debug("request for token error: ", err);
          //For lock - if we failed to request new token then we must Unlock it
          client.lockedForQuery = false;
          return cb(err);
        });
    }else{
      return cb(null, {
        accessToken: client.holder.token
      });
    }
  }

  return new QywxAccessTokenClient(options.corpId, options.corpSecret);
}
